#include<iostream>
#include<deque>
#include<cstring>
using namespace std;
int n, m;
const int N = 1010;
char a[N][N];
int dist[4][N][N];//注意dist数组第一个只开4个就行了
typedef pair<int, int> PII;
int dx[5] = { 0,0,1,-1 };
int dy[5] = { 1,-1,0,0 };

void bfs(int num)
{
	//因为多次调用bfs，所以memset重置数组
	//注意这里的传参是dist[num]
	memset(dist[num], -1, sizeof(dist[num]));
	
	deque<PII> q;
	//处理数据，把源头都加入到队列中。
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			if (a[i][j] - '0' == num)
			{
				q.push_back({ i, j });
				dist[num][i][j] = 0;
			}
		}

	while (q.size())
	{
		//正常的bfs
		PII t = q.front();q.pop_front();
		int i = t.first, j = t.second;
		for (int k = 0;k < 4;k++)
		{
			int x = i + dx[k];int y = j + dy[k];
			if (x > 0 && x <= n && y > 0 && y <= m && a[x][y] != '#')//注意咱们要判断如果是坑不能走
			{
				int w = (a[x][y] == '.' ? 1 : 0);
				//如果是国家的话那就不用走了。
				if (dist[num][x][y] == -1)
				{
					//如果第一次走到这
					dist[num][x][y] = dist[num][i][j] + w;
					//第一次走到需要插入回去
					if (w) q.push_back({ x,y });
					else q.push_front({ x,y });//如果是0则说明这是个新原点
					//01问题，原点在前。
				}
				else if (dist[num][i][j] + w < dist[num][x][y])
				{
					dist[num][x][y] = dist[num][i][j] + w;
				}
			}
			
		}
	}

}
int main()
{
	cin >> n >> m;
	//多源bfs加01bfs
	for (int i = 1;i <= n;i++)
	{
		for (int j = 1;j <= m;j++)
		{
			cin >> a[i][j];
		}
	}
	//分别找出以1，2,3为起点到某个点的距离
	bfs(1);bfs(2);bfs(3);

	//查找那个最小值
	int ret =0x3f3f3f3f;
	for (int i = 1;i <= n;i++)
	{
		for (int j = 1;j <= m;j++)
		{
			if (a[i][j] == '#') continue;
			int x = dist[1][i][j], y = dist[2][i][j], z = dist[3][i][j];
			//如果这个位置无法走到
			if (x == -1 || y == -1 || z == -1) continue;

			if (a[i][j] == '.') ret = min(ret, x + y + z-2);
			else ret = min(ret, x + y + z);//是国家的情况
		}
	}
	//如果ret保持原值不变说明无路可走
	if (ret == 0x3f3f3f3f) cout << -1 << endl;
	else cout << ret << endl;
	return 0;
}